#include "Event/Event.h"
#include "ll/api/service/Bedrock.h"

namespace XD::Event {

LL_TYPE_INSTANCE_HOOK(
    PlayerInteractEntityHook,
    HookPriority::Normal,
    Actor,
    "?handle@ItemUseOnActorInventoryTransaction@@UEBA?AW4InventoryTransactionError@@AEAVPlayer@@_N@Z",
    bool,
    ServerPlayer* player,
    bool unk
) {
    auto ev = PlayerInteractEntityEvent(*player, ll::service::getLevel()->getRuntimeEntity( *(ActorRuntimeID*)(((uintptr_t)this) + 104) ));
    ll::event::EventBus::getInstance().publish(ev);
    if (ev.isCancelled()) return true;
    return origin(player, unk);
}

LL_TYPE_INSTANCE_HOOK(
    EntityRideHook,
    HookPriority::Normal,
    Actor,
    "?canAddPassenger@Actor@@UEBA_NAEAV1@@Z",
    bool,
    Actor* a2
) {
    auto ev = EntityRideEvent(*a2);
    ll::event::EventBus::getInstance().publish(ev);
    if (ev.isCancelled()) return true;
    return origin(a2);
}

LL_TYPE_INSTANCE_HOOK(
    PistonPushHook,
    HookPriority::Normal,
    PistonBlockActor,
    &PistonBlockActor::_attachedBlockWalker,
    bool,
    BlockSource&    region,
    BlockPos const& curPos,
    uchar           curBranchFacing,
    uchar           pistonMoveFacing
) {
    if (region.getBlock(curPos).isAir()) {
        return origin(region, curPos, curBranchFacing, pistonMoveFacing);
    }
    auto ev = PistonPushEvent(region, curPos, curBranchFacing, pistonMoveFacing);
    ll::event::EventBus::getInstance().publish(ev);
    if (ev.isCancelled()) return false;
    return origin(region, curPos, curBranchFacing, pistonMoveFacing);
}

LL_TYPE_INSTANCE_HOOK(
    ExplodeHook,
    HookPriority::Normal,
    Level,
    &Level::explode,
    bool,
    BlockSource& region,
    Actor*       source,
    Vec3 const&  pos,
    float        explosionRadius,
    bool         fire,
    bool         breaksBlocks,
    float        maxResistance,
    bool         allowUnderwater
) {
    auto ev = ExplodeEvent(region, source, pos, explosionRadius);
    ll::event::EventBus::getInstance().publish(ev);
    if (ev.isCancelled()) return false;
    return origin(region, source, pos, explosionRadius, fire, breaksBlocks, maxResistance, allowUnderwater);
}

LL_TYPE_INSTANCE_HOOK(
    LiquidFlowHook,
    HookPriority::Normal,
    LiquidBlockDynamic,
    &LiquidBlockDynamic::_canSpreadTo,
    // "?_canSpreadTo@LiquidBlockDynamic@@AEBA_NAEAVBlockSource@@AEBVBlockPos@@1E@Z",
    bool,
    BlockSource&    region,
    BlockPos const& pos,
    BlockPos const& flowFromPos,
    uchar           flowFromDirection
) {
    auto ev = LiquidFlowEvent(region, pos, flowFromPos, flowFromDirection);
    ll::event::EventBus::getInstance().publish(ev);
    if (ev.isCancelled()) return false;
    return origin(region, pos, flowFromPos, flowFromDirection);
}

void playerInteractEntityEvent() { PlayerInteractEntityHook::hook(); }
void entityRideEvent()           { EntityRideHook::hook();           }
void pistonPushEvent()           { PistonPushHook::hook();           }
void explodeEvent()              { ExplodeHook::hook();              }
void liquidFlowEvent()           { LiquidFlowHook::hook();           }

} //namespace XD::Event::PlayerEvent